package org.elec.mac.inter;

import com.github.wxpay.sdk.WXPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.elec.mac.constants.Constants;
import org.elec.mac.constants.OrderConstants;
import org.elec.mac.entity.*;
import org.elec.mac.exception.ErrorCode;
import org.elec.mac.service.*;
import org.elec.mac.utils.DateUtil;
import org.elec.mac.utils.PriceUtil;
import org.elec.mac.utils.UnifiedOrder;
import org.elec.mac.utils.Utils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

@Slf4j
@Controller
@RequestMapping(value = "/order")
public class IntOrderController extends InterController {

    @Autowired
    private SMachineMenuService sMachineMenuService;

    @Autowired
    private SOrderOuttradenoService sOrderOuttradenoService;

    @Autowired
    private SUnifiedOrderService sUnifiedOrderService;

    @Autowired
    private SOrderDetailService sOrderDetailService;

    @Autowired
    private SOrderService sOrderService;

    @Autowired
    private SProductService sProductService;

    @Autowired
    private SClientWxExtendService sClientWxExtendService;

    @Value("${tencent.wx.appid}")
    private String appid;

    @Value("${tencent.wx.secret}")
    private String secret;

    @Value("${tencent.wx.key}")
    private String key;

    @Value("${tencent.wx.mchid}")
    private String mchid;

    @Value("${cert.path}")
    private String certpath;

    @Value("${tencent.wx.notifyurl}")
    private String notify_url;

    //修改订单状态
    @RequestMapping(value = "/orderstate.do")
    private void updateOrderStateHandler(HttpServletRequest request, HttpServletResponse response) throws IOException {
        JSONObject result = new JSONObject();
        int code = 0;
        result.put("code", code);
        result.put("msg", "成功");
        try {
            String orderid = request.getParameter("orderid");
            String orderstatus = request.getParameter("status");
            String outno = request.getParameter("outtradeno");
            //测试捕捉跳转动作
            String actiontest = request.getParameter("action");
            SOrder order = new SOrder();
            SOrderOuttradeno outtradeno = new SOrderOuttradeno();
            outtradeno.setOuttradeno(outno);
            outtradeno.setOid(orderid);
            order.setId(orderid);
            order.setModifyTime(new Date());
            if("UNPAID".equals(orderstatus)) {
                order.setStatus(OrderConstants.UNPAID);
                outtradeno.setStatus(OrderConstants.UNPAID);
            } else if("SUCCESS".equals(orderstatus)) {
                order.setStatus(OrderConstants.SUCCESS);
                outtradeno.setStatus(OrderConstants.SUCCESS);
            } else if("FAIL".equals(orderstatus)) {
                order.setStatus(OrderConstants.PAY_FAIL);
                outtradeno.setStatus(OrderConstants.PAY_FAIL);
            } else if("CANCEL".equals(orderstatus)) {
                order.setStatus(OrderConstants.CANCEL);
                outtradeno.setStatus(OrderConstants.CANCEL);
            } else if("FINISH".equals(orderstatus)) {
                order.setStatus(OrderConstants.FINISH);
                outtradeno.setStatus(OrderConstants.FINISH);
            } else {
                order.setStatus(OrderConstants.ORDER_FAIL);
                outtradeno.setStatus(OrderConstants.ORDER_FAIL);
            }
            sOrderService.update(order);
            sOrderOuttradenoService.update(outtradeno);
        } catch(Exception ex) {
            log.error("修改订单状态错误", ex);
            code = ErrorCode.ERR_FAILED;
            result.put("code", code);
            result.put("msg", "[" + code + "]修改订单状态错误");
        }
        response.getWriter().write(result.toString());
    }

    @RequestMapping(value = "/myorder.do")
    private void myOrderHandler(HttpServletRequest request, HttpServletResponse response) throws IOException {
        JSONObject result = new JSONObject();
        int code = 0;
        result.put("code", code);
        result.put("msg", "成功");
        try {
            String openid = request.getParameter("openid");
            Map<String, Object> param = new HashMap<>();
            param.put("userInfo", openid);
            List<Map<String, Object>> orderInfoList = sOrderService.getOrderInfoList(param);
            for(int i = 0; i < orderInfoList.size(); i++) {
                orderInfoList.get(i).put("acprice", PriceUtil.toPriceString((long)orderInfoList.get(i).get("acprice")));
                orderInfoList.get(i).put("tprice", PriceUtil.toPriceString((long)orderInfoList.get(i).get("tprice")));
                String oid = (String) orderInfoList.get(i).get("id");
                Map<String, Object> params = new HashMap<>();
                params.put("oid", oid);
                List<Map<String, Object>> orderDeteil = sOrderDetailService.orderDetails(params);
                for (int j = 0; j < orderDeteil.size(); j++) {
                    orderDeteil.get(j).put("price", PriceUtil.toPriceString((long)orderDeteil.get(j).get("price")));
                    orderDeteil.get(j).put("cprice", PriceUtil.toPriceString((long)orderDeteil.get(j).get("cprice")));
                }
                orderInfoList.get(i).put("detail", orderDeteil);
            }
            result.put("orderlist", orderInfoList);
        } catch(Exception ex) {
            log.error("查询错误", ex);
            code = ErrorCode.ERR_FAILED;
            result.put("code", code);
            result.put("msg", "[" + code + "]查询订单错误");
        }
        response.getWriter().write(result.toString());
    }

    @RequestMapping(value = "/order.do")
    private void orderHandler(HttpServletRequest request, HttpServletResponse response) throws IOException {
        JSONObject result = new JSONObject();
        int code = 0;
        result.put("code", code);
        result.put("msg", "成功");
        try {
            String tradetype = request.getParameter("tradetype");
            String id = request.getParameter("orderid");
            String outtradeno;
            SOrder order = null;
            if(StringUtils.isBlank(id)) {
                id = DateUtil.formatDate(new Date(), DateUtil.DATE_TIME_PATTERN_1 + RandomStringUtils.randomNumeric(8));
                outtradeno = id;
            } else {
                outtradeno = DateUtil.formatDate(new Date(), DateUtil.DATE_TIME_PATTERN_1 + RandomStringUtils.randomNumeric(8));
                Map<String, Object> params = new HashMap<>();
                params.put("id", id);
                order = sOrderService.get(params);
                if(order == null) {
                    log.error("orderid不存在");
                    code = ErrorCode.ERR_PARAM;
                    result.put("code", code);
                    result.put("msg", "[" + code + "]orderid不存在");
                }
            }
            if(code == 0) {
                SOrderOuttradeno sOrderOuttradeno = new SOrderOuttradeno();
                String spbill_create_ip = Utils.getIpAddress(request);
                String openid = request.getParameter("openid");
                if(StringUtils.isBlank(openid)) {
                    openid = "";
                }
                JSONArray jsonArray = new JSONArray(request.getParameter("goodsinfo"));
                Integer total = Utils.parseInt(request.getParameter("total"), Constants.UnknowInteger);
                Long tprice = PriceUtil.parse(request.getParameter("tprice"));
//              Long dprice = PriceUtil.parse(request.getParameter("dprice"));
                Long acprice = PriceUtil.parse(request.getParameter("acprice"));
                Integer paymode = Utils.parseInt(request.getParameter("paymode"), Constants.UnknowInteger);
                String machserial = request.getParameter("machserial");

                if(checkGoodsInfoAndAcprice(machserial, jsonArray, 0L, acprice, total)) {
                    if(paymode == 1) {
                        if(order != null) {
                            order.setOutTradeno(outtradeno);
                            order.setStatus(OrderConstants.INIT);
                            sOrderService.update(order);
                        } else {
                            order = new SOrder();
                            order.setId(id);
                            order.setUserInfo(openid);
                            order.setPaymode(paymode);
                            order.setOutTradeno(outtradeno);
                            order.setRefund(false);
                            order.setRefstat(0);
                            order.setPayMsg("");
                            order.setStatus(OrderConstants.INIT);
                            order.setTotal(total);
                            order.setTprice(tprice);
                            order.setAcprice(acprice);
                            order.setCreateTime(new Date());
                            order.setModifyTime(new Date());
                            sOrderService.insert(order);

                            SOrderDetail sOrderDetail = new SOrderDetail();
                            for(int i = 0; i < jsonArray.length(); i++) {
                                JSONObject goods = (JSONObject) jsonArray.get(i);
                                sOrderDetail.setCounts(goods.getInt("counts"));
                                sOrderDetail.setCprice(PriceUtil.parse(goods.get("cprice").toString()));
                                sOrderDetail.setOid(order.getId());
                                sOrderDetail.setPid(goods.getLong("pid"));
                                sOrderDetail.setPrice(PriceUtil.parse(goods.get("price").toString()));
                                try {
                                    String materials = goods.getString("materials");
                                    sOrderDetail.setMaterials(materials);
                                } catch(Exception ex) {
                                    Map<String, Object> param = new HashMap<>();
                                    param.put("id", goods.getLong("pid"));
                                    SProduct sProduct = sProductService.get(param);
                                    sOrderDetail.setMaterials(sProduct.getMaterials());
                                }
                                sOrderDetailService.insert(sOrderDetail);
                            }
                        }
                        result.put("orderid", order.getId());
                        result.put("outtradeno", order.getOutTradeno());

                        sOrderOuttradeno.setOid(id);
                        sOrderOuttradeno.setOuttradeno(outtradeno);
                        sOrderOuttradeno.setStatus(OrderConstants.INIT);
                        sOrderOuttradeno.setCreateTime(new Date());
                        sOrderOuttradenoService.insert(sOrderOuttradeno);

                        //扫码支付
                        if("NATIVE".equals(tradetype)) {
                            long time_stamp = System.currentTimeMillis() / 1000;
                            String product_id = id;
                            String key = this.key; // key

                            Map<String, String> packageParams = new HashMap<>();
                            packageParams.put("appid", this.appid);
                            packageParams.put("mch_id", this.mchid);
                            packageParams.put("time_stamp", String.valueOf(time_stamp));
                            packageParams.put("nonce_str", WXPayUtil.generateNonceStr());
                            packageParams.put("product_id", product_id + "_" + machserial);
                            try {
                                String sign = WXPayUtil.generateSignature(packageParams, key);
                                packageParams.put("sign", sign);
                            } catch(Exception e) {
                                e.printStackTrace();
                            }

                            //生成参数
                            String str = ToUrlParams(packageParams);
                            String payurl = "weixin://wxpay/bizpayurl?" + str;
                            log.info("payurl:" + payurl);
                            result.put("pay_url", payurl);
                        } else {
                            //记录openid
                            Map<String, Object> param = new HashMap<>();
                            param.clear();
                            param.put("openid", openid);
                            SClientWxExtend sClientWxExtend = sClientWxExtendService.get(param);
                            if(sClientWxExtend != null) {
                                sClientWxExtend.setOpenid(openid);
                                sClientWxExtend.setOrdercount(0);
                                sClientWxExtend.setCreatetime(new Date());
                                sClientWxExtendService.insert(sClientWxExtend);
                            }
                            //微信下单
                            result = UnifiedOrder.order(id, machserial, openid, tradetype, result, outtradeno, spbill_create_ip, acprice, appid, mchid, key, certpath, notify_url, sUnifiedOrderService);
                        }
                    }
                    if(Objects.equals(result.get("code"), 0)) {
                        order.setStatus(OrderConstants.PAYING);
                        sOrderService.update(order);
                        sOrderOuttradeno.setStatus(OrderConstants.PAYING);
                        sOrderOuttradenoService.update(sOrderOuttradeno);
                    } else {
                        order.setStatus(OrderConstants.ORDER_FAIL);
                        sOrderService.update(order);
                        sOrderOuttradeno.setStatus(OrderConstants.ORDER_FAIL);
                        sOrderOuttradenoService.update(sOrderOuttradeno);
                    }
                } else {
                    log.error("提交订单商品信息或价格与后台不匹配");
                    code = ErrorCode.ERR_FAILED;
                    result.put("code", code);
                    result.put("msg", "[" + code + "]提交订单商品信息或价格与后台不匹配");
                }
            }
        } catch(Exception ex) {
            log.error("提交订单错误", ex);
            code = ErrorCode.ERR_FAILED;
            result.put("code", code);
            result.put("msg", "[" + code + "]提交订单错误");
        }
        response.getWriter().write(result.toString());
    }

    public String ToUrlParams(Map<String, String> packageParams) {
        //实际可以不排序
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if(null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }

        sb.deleteCharAt(sb.length() - 1);//删掉最后一个&
        return sb.toString();
    }

    /**
     * 检验上传商品信息与后台产品信息是否匹配
     *
     * @param jsonArray 商品信息
     * @param dprice    优惠金额
     * @param acprice   实际支付金额
     * @param total     总数
     * @return 是否匹配
     */
    private boolean checkGoodsInfoAndAcprice(String machserial, JSONArray jsonArray, Long dprice, Long acprice, Integer total) {
        Map<String, Object> params = new HashMap<>();
        Long gcprice = 0L;
        Integer gtotal = 0;
        if(jsonArray.length() > 0) {
            log.info(jsonArray.toString());
            for(int i = 0; i < jsonArray.length(); i++) {
                JSONObject goods = (JSONObject) jsonArray.get(i);
                log.info(goods.toString());
                params.put("machid", machserial);
                params.put("pid", goods.get("pid"));
                List<Map<String, Object>> machineMenuList = sMachineMenuService.getMachineMenuList(params);
                if(machineMenuList.size() == 0) {
                    return false;
                }
                Map<String, Object> machineMenu = machineMenuList.get(0);
                params.clear();

                if(goods.get("productname").equals(machineMenu.get("productname"))
                        && goods.get("description").equals(machineMenu.get("description"))
                        && Objects.equals(goods.get("price").toString(), PriceUtil.toPriceString(Utils.parseLong(machineMenu.get("price").toString(),0)))
                        && Objects.equals(goods.get("cprice").toString(), PriceUtil.toPriceString(Utils.parseLong(machineMenu.get("cprice").toString(),0)))) {
                    gcprice += goods.getInt("counts") * (Long) machineMenu.get("cprice");
                    gtotal += goods.getInt("counts");
                } else {
                    return false;
                }
            }
            if(acprice == gcprice - dprice && Objects.equals(total, gtotal)) {
                return true;
            }
        }
        return false;
    }
}
